#include <functional>
#include <future>
#include <memory>
#include <string>
#include <sstream>

#include "test_interfaces/action/fibonacci.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

// 用于请求计算斐波那契数列
class FibonacciActionClient : public rclcpp::Node
{
public:
    using Fibonacci = test_interfaces::action::Fibonacci;                   // 动作类型定义
    using GoalHandleFibonacci = rclcpp_action::ClientGoalHandle<Fibonacci>; // 目标的句柄

    // 类型定义
    explicit FibonacciActionClient(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
        : Node("fibonacci_action_client", options) // 创建节点并命名 "fibonacci_action_client"
    {
        // 创建了客户端 client_ptr_ 来连接动作服务器 fibonacci
        this->client_ptr_ = rclcpp_action::create_client<Fibonacci>(
            this,
            "fibonacci");

        this->timer_ = this->create_wall_timer(
            std::chrono::milliseconds(500),
            std::bind(&FibonacciActionClient::send_goal, this));
    }

    // 发送目标请求
    void send_goal()
    {
        using namespace std::placeholders;

        this->timer_->cancel(); // 停止定时器避免重复发送目标

        if (!this->client_ptr_->wait_for_action_server()) // 阻塞等待连接服务器，若连接失败则打印错误并关闭节点
        {
            RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");
            rclcpp::shutdown();
        }

        auto goal_msg = Fibonacci::Goal(); // 斐波那契的消息对象
        goal_msg.order = 10;

        RCLCPP_INFO(this->get_logger(), "Sending goal");

        auto send_goal_options = rclcpp_action::Client<Fibonacci>::SendGoalOptions(); // 创建一个SendGoalOptions对象 send_goal_options，用于配置发送目标的回调函数

        // 设置目标响应回调函数，std：：bind 绑定了 goal_response_callback 函数，将其与当前实例this关联，并使用占位符 _1 接收回调函数的第一个参数
        send_goal_options.goal_response_callback =
            std::bind(&FibonacciActionClient::goal_response_callback, this, _1);
        // 设置反馈回调函数，回调函数 feedback_callback 接收两个参数 _1(目标句柄)和 _2(反馈消息)
        send_goal_options.feedback_callback =
            std::bind(&FibonacciActionClient::feedback_callback, this, _1, _2);
        // 设置结果回调函数，result_back 将接收服务器返回的结果信息
        send_goal_options.result_callback =
            std::bind(&FibonacciActionClient::result_callback, this, _1);

        // 异步发送目标消息 goal_msg 和 回调配置，异步发送意味着目标请求会立即返回，不会阻塞客户端进程
        this->client_ptr_->async_send_goal(goal_msg, send_goal_options);
    }

private:
    rclcpp_action::Client<Fibonacci>::SharedPtr client_ptr_;
    rclcpp::TimerBase::SharedPtr timer_;

    void goal_response_callback(const GoalHandleFibonacci::SharedPtr &goal_handle)
    {
        if (!goal_handle)
        {
            RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");
        }
        else
        {
            RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");
        }
    }

    void feedback_callback(
        GoalHandleFibonacci::SharedPtr,
        const std::shared_ptr<const Fibonacci::Feedback> feedback)
    {
        std::stringstream ss;
        ss << "Next number in sequence received: ";
        for (auto number : feedback->partial_sequence)
        {
            ss << number << " ";
        }
        RCLCPP_INFO(this->get_logger(), ss.str().c_str());
    }

    void result_callback(const GoalHandleFibonacci::WrappedResult &result)
    {
        switch (result.code)
        {
        case rclcpp_action::ResultCode::SUCCEEDED:
            break;
        case rclcpp_action::ResultCode::ABORTED:
            RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
            return;
        case rclcpp_action::ResultCode::CANCELED:
            RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
            return;
        default:
            RCLCPP_ERROR(this->get_logger(), "Unknown result code");
            return;
        }
        std::stringstream ss;
        ss << "Result received: ";
        for (auto number : result.result->sequence)
        {
            ss << number << " ";
        }
        RCLCPP_INFO(this->get_logger(), ss.str().c_str());
        rclcpp::shutdown();
    }
};